from datetime import date
from time import localtime, strftime
from typing import Tuple, Callable
import sxtwl

# 简化的日期交换类型
YMD = Tuple[int, int, int]
# 节日配置项类型
HOLIDAY_CFG = Tuple[str, int, int, bool]
# 节日转换结果类型
HOLIDAY_RES = Tuple[str, int]
# 避免魔法数字
FRIDAY = 4
# 节日配置
# 节日名，月，日，是否为农历
HOLIDAY_CONFIGS = [
    ('元旦', 1, 1, False),
    ('春节', 1, 1, True),
    ('清明', 4, 5, False),
    ('五一', 5, 1, False),
    ('端午', 5, 5, True),
    ('中秋', 8, 15, True),
    ('国庆', 10, 1, False),
]

# 对节日类型的包装
class Holiday:
  def __init__(self,  name: str, ymd: YMD, isLunar:bool = False) -> None:
      self.year, self.month, self.day = ymd
      self.ymd = ymd
      self.name = name
      self.isLunar = isLunar
  
  # 辅助方法，将自身的年份向后更新一年
  def nextYear(self) -> None:
    y,m,d = self.ymd
    y += 1
    self.ymd = (y,m,d)
    self.year = y

  # 获取公历日期
  def getSolarDate(self) -> date:
    return date(*(self.ymd if not self.isLunar else lunarToSolar(sxtwl.fromLunar(*self.ymd))))
  
  # 计算这个节是否在目标日之前
  def isBefore(self, targetDate: date) -> bool:
      return True if self.getSolarDeltaOf(targetDate) < 0 else False

  # 计算节日和目标日之间的差值
  def getSolarDeltaOf(self, targetDate: date) -> int:
      return daysBetween(self.getSolarDate(), targetDate)

# 计算日期距离的辅助函数
def daysBetween(date1:date, date2:date) -> int :
  return (date1 - date2).days

# 农历日期转公历日期的辅助函数
def lunarToSolar(lunarDate: sxtwl.Day) -> YMD:
  return (lunarDate.getSolarYear(), lunarDate.getSolarMonth(), lunarDate.getSolarDay())

# 计算距离周末日期的辅助函数
def closestWeekend(targetDate: date) -> HOLIDAY_RES:
  delta = FRIDAY - targetDate.weekday()
  return ('周末', delta if delta > -1 else 0)

# 转换配置到日期差的辅助函数
def holidayMaker(today: date) -> Callable[[HOLIDAY_CFG], HOLIDAY_RES]:
  def helper(config: HOLIDAY_CFG) -> HOLIDAY_RES:
    # 获取配置项
    name, *md, isLunar = config
    # 构造节日对象
    holiday = Holiday(name, (today.year, *md), isLunar)
    # 过今年还是明年的节
    if holiday.isBefore(today):
      holiday.nextYear()
    # 获取剩余的时间
    delta = holiday.getSolarDeltaOf(today)
    return (holiday.name, delta)
  return helper


# 总的转换流程
def transform(today: date) -> list[HOLIDAY_RES]:
  hMaker = holidayMaker(today)
  # 转换，添加周末信息，按照时间顺序排序
  holidayResult = sorted(
    [*map(hMaker,HOLIDAY_CONFIGS),closestWeekend(today)]
    , key = lambda x: x[1])
  return holidayResult

# 示例提示语
def demo_toast() -> str:
    today = date.today()
    # 工作日提示辅助函数，以后再用吧
    # def weekdayHandler() -> str:
    #   greetings = [
    #     '周一周一你妈个b',
    #     '群内摸鱼',
    #     '群内摸鱼',
    #     '狂乱木曜日，v我50',
    #     '这周这个b班就上到这',
    #     '',
    #     '',
    #   ]
    #   return greetings[today.weekday()]
    # 时间提示辅助函数
    def timeHandler() -> str:
      # 获取当前小时（24小时制）
      currentHour = int(strftime('%H', localtime()))
      HINT = '有事没事起身去茶水间，去厕所，去廊道走走，别老在工位上坐着。钱是老板的，命是自己的。'
      greeting = '晚上好，早点睡。'
      cases = [
        '该睡了，小命要紧。',
        '早上好。出门了吗？',
        f'上午好。{HINT}',
        f'中午好，该恰饭了。{HINT}',
        f'下午好，饮茶先啦！{HINT}',
        '傍晚好，下班了吗？',
      ]
      timeBound = [0,6,9,11,13,18,20]
      # range都是左闭右开
      for status in range(0, len(timeBound) - 1):
        # 切片时间段
        times = timeBound[status:status+2]
        # 找到时间段 - 寒暄语的对应关系
        if currentHour in range(*times):
          greeting = cases[status]
      return greeting
    
    # 组装辅助函数
    def composer() -> str:
      return f'今天是{today.month}月{today.day}日，摸鱼人，{timeHandler()}'
    
    # 提示语辅助函数
    def toast(toaster: str, *toasts: str) -> str:
        preparedToast = '\n'.join(toasts)
        return f'【{toaster}】{preparedToast}'
    
    # 节日格式化函数
    def noticeMaker(config):
        holiday, rest = config
        return f'距离【{holiday}】还有:{rest}天'

    holidayDeltas = transform(today)
    holidayInfo = '\n'.join(map(noticeMaker, holidayDeltas))
    return toast('群摸鱼办', composer(), holidayInfo)

def main():
  print(demo_toast())
    
if __name__ == '__main__':
  main()